#ifndef __SHM_HPP__
#define __SHM_HPP__

#include<iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string>
#include<cstdio>
#include<unistd.h>
#include<cstring>

const std::string pathname="/home/liujj/liujj/4.shm";
const int Create=1;
const int User=2;
const int Size=4096;


class Shm
{
private:
int ShmGetHelper(key_t key,int size,int flag)
    {
        _shmid=shmget(key,size,flag);
        if(_shmid<0)
        {
            perror("creat shm");
        }
        std::cout<<"shm create"<<std::endl;   
        return _shmid;
    }

    key_t GetCommandKey(const std::string &pathname,int proj_id)
    {
        _key= ftok(pathname.c_str(),proj_id);
        if(_key<0)
        {
            perror("ftok");
        }
        return _key;
    }

    void *AttachShm()
    {
        void *shmaddr=shmat(_shmid,nullptr,0);
        if(shmaddr==nullptr)
        {
            perror("shmat");
        }

        return shmaddr;
    }

    void DetachShm(const void *shmaddr)
    {
        if(shmaddr==nullptr)return;
        int n=shmdt(shmaddr);
    }

public:
    Shm(const std::string &pathname,int proj_id,int who)
    :_pathname(pathname),_proj_id(proj_id),_who(who),_addr(nullptr)
    {
         GetCommandKey(_pathname,_proj_id);
         if(_who==Create)GetShmCreater();
         else if(_who==User)GetShmUser();

         _addr=AttachShm();

         std::cout<<"shmid:"<<_shmid<<",key:"<<ToHex(_key)<<std::endl;
    }
    ~Shm()
    {
        DetachShm(_addr);
        if(_who==Create)
        {
            int n=shmctl(_shmid,IPC_RMID,nullptr);
            std::cout<<"shm delete"<<std::endl;
        }
        
    }

    std::string ToHex(key_t k)
    {
        char buffer[128];
        snprintf(buffer,sizeof(buffer),"0x%x",_key);
        return buffer;
    }
    bool GetShmCreater()
    {
        if(_who==Create)
        {
            _shmid=ShmGetHelper(_key,Size,IPC_CREAT | IPC_EXCL | 0666);
            if(_shmid>=0)
                return true;
        }
        return false;
    }
    bool GetShmUser()
    {
        if(_who==User)
        {
            _shmid=ShmGetHelper(_key,Size,IPC_CREAT | 0666);
            if(_shmid>=0)return true;
             std::cout<<"shm get"<<std::endl;
        }
        return false;
    }

    void CleanMemory()
    {
        if(_addr)
        {
            memset(_addr,0,Size);
        }
    }
    void *GerAddr()
    {
        return _addr;
    }

private:
    key_t _key;
    int _shmid;
    std::string _pathname;
    int _proj_id;
    int _who;
    void *_addr;
};


#endif